package com.itheima.stock.task.service.impl;

import com.google.common.collect.Lists;
import com.itheima.stock.config.StockInfoConfig;
import com.itheima.stock.mapper.*;
import com.itheima.stock.pojo.StockBlockRtInfo;
import com.itheima.stock.pojo.StockMarketIndexInfo;
import com.itheima.stock.pojo.StockOuterMarketIndexInfo;
import com.itheima.stock.pojo.StockRtInfo;
import com.itheima.stock.task.service.StockTimerTaskService;
import com.itheima.stock.utils.DateTimeUtil;
import com.itheima.stock.utils.IdWorker;

import com.itheima.stock.utils.ParseType;
import com.itheima.stock.utils.ParserStockInfoUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

/**
 * @author by itheima
 * @Date 2022/6/5
 * @Description 定义股票数据采集服务实现
 */
@Service("stockTimerTaskService")
@Slf4j
public class StockTimerTaskServiceImpl implements StockTimerTaskService {
    /**
     * 注入httpClinet bean，调用远程股票api接口
     */
    @Autowired
    private RestTemplate restTemplate;

    /**
     * 注入股票参数配置类，方便获取股票相关的url地址信息
     */
    @Autowired
    private StockInfoConfig stockInfoConfig;

    /**
     * 注入id生成器，方便生成主键id值
     */
    @Autowired
    private IdWorker idWorker;

    @Autowired
    private StockMarketIndexInfoMapper stockMarketIndexInfoMapper;

    @Autowired
    private StockBusinessMapper stockBusinessMapper;

    @Autowired
    private ParserStockInfoUtil parserStockInfoUtil;

    @Autowired
    private StockRtInfoMapper stockRtInfoMapper;

    @Autowired
    private StockBlockRtInfoMapper stockBlockRtInfoMapper;

    @Autowired
    private StockOuterMarketIndexInfoMapper stockOuterMarketIndexInfoMapper;

    /**
     * 注入线程池对象
     */
    @Autowired
    private ThreadPoolTaskExecutor threadPoolTaskExecutor;

    @Override
    public void getInnerMarketInfo() {
        //1.组装url地址 eg:http://hq.sinajs.cn/list=sz000002,sh600015
        String innerMarketUrl = stockInfoConfig.getMarketUrl() + String.join(",", stockInfoConfig.getInner());
        //2.其它参数
        String referer = "http://finance.sina.com.cn/realstock/company/sh000001/nc.shtml";
        String userAgent = "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.121 Safari/537.36";
        //3.组装http请求对象
        //3.1 组装请求头
        //设置请求头的请求参数类型
        HttpHeaders headers = new HttpHeaders();
        headers.add("Referer", referer);
        headers.add("User-Agent", userAgent);
        //3.2 组装请求对象
        HttpEntity<Object> entity = new HttpEntity<>(headers);
        //4.发送请求
        String result = restTemplate.postForObject(innerMarketUrl, entity, String.class);
        System.out.println(result);
        if (result == null) {
            return;
        }
        /*
        var hq_str_sh000001="上证指数,3170.3055,3182.1566,3195.4580,3197.2818,3163.7555,0,0,361770632,413729263917,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2022-06-02,15:30:39,00,";
        var hq_str_sz399001="深证成指,11492.966,11551.272,11628.309,11637.534,11470.891,0.000,0.000,40615805083,477859353737.149,0,0.000,0,0.000,0,0.000,0,0.000,0,0.000,0,0.000,0,0.000,0,0.000,0,0.000,0,0.000,2022-06-02,15:00:03,00";
         */
        //定义公共正则表达式
        String reg = "var hq_str_(.+)=\"(.+)\";";
        //编译表达式获取pattern对象
        Pattern pattern = Pattern.compile(reg);
        //匹配
        Matcher matcher = pattern.matcher(result);
        //收集解析的大盘数据实体对象
        List<StockMarketIndexInfo> list = new ArrayList<>();
        while (matcher.find()) {
            String marketCode = matcher.group(1);
            //以逗号间隔的其它信息
            String otherInfos = matcher.group(2);
            //解析获取大盘基础数据
            String[] splitArr = otherInfos.split(",");
            //大盘名称
            String marketName = splitArr[0];
            //获取当前大盘的开盘点数
            BigDecimal openPoint = new BigDecimal(splitArr[1]);
            //前收盘点
            BigDecimal preClosePoint = new BigDecimal(splitArr[2]);
            //获取大盘的当前点数
            BigDecimal curPoint = new BigDecimal(splitArr[3]);
            //获取大盘最高点
            BigDecimal maxPoint = new BigDecimal(splitArr[4]);
            //获取大盘的最低点
            BigDecimal minPoint = new BigDecimal(splitArr[5]);
            //获取成交量
            Long tradeAmt = Long.valueOf(splitArr[8]);
            //获取成交金额
            BigDecimal tradeVol = new BigDecimal(splitArr[9]);
            //时间
            Date curTime = DateTimeUtil.getDateTimeWithoutSecond(splitArr[30] + " " + splitArr[31]).toDate();
            //组装大盘实体对象
            //组装entity对象
            StockMarketIndexInfo info = StockMarketIndexInfo.builder()
                    .id(idWorker.nextId() + "")
                    .marketCode(marketCode)
                    .marketName(marketName)
                    .curPoint(curPoint)
                    .openPoint(openPoint)
                    .preClosePoint(preClosePoint)
                    .maxPoint(maxPoint)
                    .minPoint(minPoint)
                    .tradeVolume(tradeVol)
                    .tradeAmount(tradeAmt)
                    .curTime(curTime)
                    .build();
            list.add(info);
        }
        log.info("当前采集的数据数量：{},内容：{}", list.size(), list);
        //批量插入
        int count = stockMarketIndexInfoMapper.insertBatch(list);
        log.info("当前插入了：{}条数据", count);
    }

    /**
     * 采集A股实时数据方法
     */
    @Override
    public void getStockAShare() {
        //查询所有A股股票的编码
        List<String> allCodes = stockBusinessMapper.getAllStockCodes();
        //添加股票前缀
        List<String> prefixCodes = allCodes.stream().map(code -> {
            code = code.startsWith("6") ? "sh" + code : "sz" + code;
            return code;
        }).collect(Collectors.toList());
        //股票编码集合分片处理
        //设置请求头的请求参数类型
        HttpHeaders headers = new HttpHeaders();
        headers.add("Referer", "https://finance.sina.com.cn/stock/");
        headers.add("User-Agent", "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.121 Safari/537.36");
        HttpEntity<Object> entity = new HttpEntity<>(headers);
        //要求：将集合分组，每组的集合长度为15
        Lists.partition(prefixCodes, 15).forEach(codeList -> {
            //每个分片的数据开启一个线程异步执行任务
            threadPoolTaskExecutor.execute(() -> {
                //组装请求地址
                String url = stockInfoConfig.getMarketUrl() + String.join(",", codeList);
                String result = restTemplate.postForObject(url, entity, String.class);
                if (result == null) {
                    return;
                }
                //解析数据，并封装对象
                List<StockRtInfo> list = parserStockInfoUtil.parser4StockOrMarketInfo(result, ParseType.ASHARE);
                //批量保存
                int count = stockRtInfoMapper.insertBatch(list);
                log.info("插入记录数：{}条，内容：{}", count, list);
            });
            });


    }

    /**
     * 板块实时数据拉取实现
     */
    @Override
    public void getStockSectorRtIndex() {
        //组装url地址
        String blockUrl = stockInfoConfig.getBlockUrl();
        //组装http请求对象
        String result = restTemplate.getForObject(blockUrl, String.class);
        //数据格式：
        // "new_blhy,玻璃行业,19,19.293684210526,-0.17052631578947,-0.87610188740468,315756250,5258253314,sh600586,3.464,9.260,0.310,金晶科技"
        //解析数据
        List<StockBlockRtInfo> stockBlockRtInfos = parserStockInfoUtil.parse4StockBlock(result);

        Lists.partition(stockBlockRtInfos, 20).forEach(list -> {
            //每个分片的数据开启一个线程异步执行任务
            threadPoolTaskExecutor.execute(()->{
            //20个一组，批量插入
            stockBlockRtInfoMapper.insertBatch(list);
        });
    });
        log.info("板块数据量：{},内容{}", stockBlockRtInfos.size(),stockBlockRtInfos);
    }
    /**
     * 外盘数据采集定时任务
     */
    @Override
    public void getStockOuterInfos() {
          //1.组装url地址 eg:http://hq.sinajs.cn/list=sz000002,sh600015
        String outerMarketUrl = stockInfoConfig.getMarketUrl() + String.join(",", stockInfoConfig.getOuter());
        //2.其它参数
        String referer = "https://vip.stock.finance.sina.com.cn/mkt/";
        String userAgent = "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.121 Safari/537.36";
        //3.组装http请求对象
        //3.1 组装请求头
        //设置请求头的请求参数类型
        HttpHeaders headers = new HttpHeaders();
        headers.add("Referer", referer);
        headers.add("User-Agent", userAgent);
        //3.2 组装请求对象
        HttpEntity<Object> entity = new HttpEntity<>(headers);
        //4.发送请求
        String result = restTemplate.postForObject(outerMarketUrl, entity, String.class);
        System.out.println(result);
        if (result == null) {
            return;
        }
        //解析数据
        //定义正则表达式
        String reg = "var hq_str_(.+)=\"(.+)\";";
        //编译表达式获取pattern对象
        Pattern pattern = Pattern.compile(reg);
        //匹配数据
        Matcher matcher = pattern.matcher(result);
        //收集解析的大盘数据实体对象
        ArrayList<StockOuterMarketIndexInfo> list = new ArrayList<>();
        while (matcher.find()){
            //获取股票id
            String marketCode = matcher.group(1);
            //获取以逗号间隔的其他信息
            String othersInfos = matcher.group(2);
            //调用工具类解析封装数据
            StockOuterMarketIndexInfo info = parserStockInfoUtil.parser4OuterStockMarket(marketCode, othersInfos);
            list.add(info);
        }
        log.info("当前采集的数据数量：{},内容：{}", list.size(), list);
        //批量插入数据
        stockOuterMarketIndexInfoMapper.insertBatch(list);

    }
}
